package brainfsck

import chisel3._
import circt.stage.ChiselStage

class NvboardTop extends Module {
    val io = IO(new Bundle {
        val rx = Input(UInt(1.W))
        val tx = Output(UInt(1.W))
    })

    private val mem = Module(new DataMem(8))
    private val rom = Module(new SimulatedRom(10, "src/main/bf/tolower.bf"))
    private val core = Module(new Brainfsck(10))
    private val uartRx = Module(new UartRx)
    private val uartTx = Module(new UartTx)
    private val inputBuffer = Module(new CrossBuffer(8))
    private val outputBuffer = Module(new CrossBuffer(8))

    private val uartClkDiv = 15.U(4.W)
    private val uartCounter = RegInit(uartClkDiv)
    private val uartCe = RegInit(false.B)
    uartCounter := Mux(uartCounter>=uartClkDiv, 0.U, uartCounter+1.U)
    uartCe := Mux(uartCounter>=uartClkDiv, true.B, false.B)

    core.io.memPort <> mem.io
    core.io.romPort <> rom.io
    core.io.inputPort <> inputBuffer.io.readPort
    core.io.outputPort <> outputBuffer.io.writePort
    inputBuffer.io.writePort <> uartRx.io.dataPort
    outputBuffer.io.readPort <> uartTx.io.dataPort
    inputBuffer.io.writeCe := uartCe
    inputBuffer.io.readCe := true.B
    outputBuffer.io.writeCe := true.B
    outputBuffer.io.readCe := uartCe
    uartRx.io.ce := uartCe
    uartTx.io.ce := uartCe
    uartRx.io.rx := io.rx
    io.tx := uartTx.io.tx
}

object NvboardTop extends App {
    private val chiselStageArgs = Array(
        "Elaborate",
        "--target-dir", "target/src/main/sv",
    )

    // additional firrtl options
    // see https://github.com/OSCPU/chisel-playground
    // and https://github.com/chipsalliance/chisel/blob/main/src/test/scala-2/circtTests/stage/ChiselStageSpec.scala
    private val firtoolOptions = Array(
            "--lowering-options=" + List(
            // make yosys happy
            // see https://github.com/llvm/circt/blob/main/docs/VerilogGeneration.md
            "disallowLocalVariables",
            "disallowPackedArrays",
            "locationInfoStyle=wrapInAtSquareBracket"
        ).reduce(_ + "," + _)
    )

    ChiselStage.emitSystemVerilogFile(new NvboardTop, chiselStageArgs, firtoolOptions)
}
